package edu.put.sk.nrpp;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author kevin
 * TODO: rewrite this (using only _data field) without calculating data in constructor.
 */
public class IPPacket {
	private int version;
	private int headerLength;
	private int DSCP;
	private int ECP;
	private int totalLength;
	private int identification;
	private int flags;
	private int fragmentOffset;
	private int timeToLive;
	private int protocol;
	private int headerChecksum;
	private InetAddress sourceAddress;
	private InetAddress destinationAddress;
	private int options;
	public Bit[] data;
	public Bit[] bits;
	
	
	
	public IPPacket(byte[] data){
		Bit[] bitsData= Bit.parseByte(data);
		version=(Bit.toInt(Bit.cut(bitsData, 0, 3)));
		headerLength=Bit.toInt(Bit.cut(bitsData, 4, 7));
		DSCP=(Bit.toInt(Bit.cut(bitsData, 8, 13)));
		setECP(Bit.toInt(Bit.cut(bitsData, 14, 15)));
		setTotalLength(Bit.toInt(Bit.cut(bitsData, 16, 31)));
		setIdentification(Bit.toInt(Bit.cut(bitsData, 32, 47)));
		setFlags(Bit.toInt(Bit.cut(bitsData, 48, 50)));
		setFragmentOffset(Bit.toInt(Bit.cut(bitsData, 52, 63)));
		setTimeToLive(Bit.toInt(Bit.cut(bitsData, 64, 71)));
		protocol=(Bit.toInt(Bit.cut(bitsData, 72, 79)));
		setHeaderChecksum(Bit.toInt(Bit.cut(bitsData, 80, 95)));
		this.bits=Bit.cut(bitsData, 0, (data.length-1)*8-1);
		
		
		byte[] sourAdd=new byte[4];
		sourAdd[0]=Bit.toByte(Bit.cut(bitsData, 96, 103));
		sourAdd[1]=Bit.toByte(Bit.cut(bitsData, 104, 111));
		sourAdd[2]=Bit.toByte(Bit.cut(bitsData, 112, 119));
		sourAdd[3]=Bit.toByte(Bit.cut(bitsData, 120, 127));
		byte[] destAdd=new byte[4];
		destAdd[0]=Bit.toByte(Bit.cut(bitsData, 128, 135));
		destAdd[1]=Bit.toByte(Bit.cut(bitsData, 136, 143));
		destAdd[2]=Bit.toByte(Bit.cut(bitsData, 144, 151));
		destAdd[3]=Bit.toByte(Bit.cut(bitsData, 152, 159));
		try {
			setSourceAddress(InetAddress.getByAddress(sourAdd));
			setDestinationAddress(InetAddress.getByAddress(destAdd));
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		int endPosition=159;
		if(headerLength>5){
			endPosition=159+32*(headerLength-5);
			setOptions(Bit.toInt(Bit.cut(bitsData, 160, endPosition)));
		}
		
		this.data=Bit.cut(bitsData, headerLength*32,  this.bits.length-1);
		

		
		
		
//		System.out.println("IPPACket sor:"+sourceAddress.toString()+"\tdest: "+destinationAddress.toString()+"\tprot: "+getProtocol());
		
		
	}

	/**
	 * @return the version
	 */
	public int getVersion() {
		return version;
	}



	/**
	 * @return the dSCP
	 */
	public int getDSCP() {
		return DSCP;
	}


	/**
	 * @return the protocol
	 */
	public int getProtocol() {
		return protocol;
	}
	

	/**
	 * @return the IP data field
	 */
	public Bit[] getData() {
		return data;
	}

	/**
	 * @param eCP the eCP to set
	 */
	public void setECP(int eCP) {
		ECP = eCP;
	}

	/**
	 * @return the eCP
	 */
	public int getECP() {
		return ECP;
	}

	/**
	 * @param identification the identification to set
	 */
	public void setIdentification(int identification) {
		this.identification = identification;
	}

	/**
	 * @return the identification
	 */
	public int getIdentification() {
		return identification;
	}

	/**
	 * @param flags the flags to set
	 */
	public void setFlags(int flags) {
		this.flags = flags;
	}

	/**
	 * @return the flags
	 */
	public int getFlags() {
		return flags;
	}

	/**
	 * @param fragmentOffset the fragmentOffset to set
	 */
	public void setFragmentOffset(int fragmentOffset) {
		this.fragmentOffset = fragmentOffset;
	}

	/**
	 * @return the fragmentOffset
	 */
	public int getFragmentOffset() {
		return fragmentOffset;
	}

	/**
	 * @param timeToLive the timeToLive to set
	 */
	public void setTimeToLive(int timeToLive) {
		this.timeToLive = timeToLive;
	}

	/**
	 * @return the timeToLive
	 */
	public int getTimeToLive() {
		return timeToLive;
	}

	/**
	 * @param headerChecksum the headerChecksum to set
	 */
	public void setHeaderChecksum(int headerChecksum) {
		this.headerChecksum = headerChecksum;
	}

	/**
	 * @return the headerChecksum
	 */
	public int getHeaderChecksum() {
		return headerChecksum;
	}

	/**
	 * @param options the options to set
	 */
	public void setOptions(int options) {
		this.options = options;
	}

	/**
	 * @return the options
	 */
	public int getOptions() {
		return options;
	}

	/**
	 * @param destinationAddress the destinationAddress to set
	 */
	public void setDestinationAddress(InetAddress destinationAddress) {
		this.destinationAddress = destinationAddress;
	}

	/**
	 * @return the destinationAddress
	 */
	public InetAddress getDestinationAddress() {
		return destinationAddress;
	}

	/**
	 * @param sourceAddress the sourceAddress to set
	 */
	public void setSourceAddress(InetAddress sourceAddress) {
		this.sourceAddress = sourceAddress;
	}

	/**
	 * @return the sourceAddress
	 */
	public InetAddress getSourceAddress() {
		return sourceAddress;
	}

	/**
	 * @param totalLength the totalLength to set
	 */
	public void setTotalLength(int totalLength) {
		this.totalLength = totalLength;
	}

	/**
	 * @return the totalLength
	 */
	public int getTotalLength() {
		return totalLength;
	}
}
